#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "munit.h"

#if defined(_MSC_VER)
#pragma warning(disable: 4127)
#endif

#include "scorecache.h"

/* START for tests for BGe scoring etc */
#ifdef BLAS
#include "bge_matrix.h"
#include "bge_posterior.h"
#include "bge_score.h"

/* Declare test data sets - BEGIN */

/* declares a continuous test dataset for scoring a 3 node belief network
 * (dataset from D. Geiger & D. Heckerman "Learning Gaussian Networks" 1994) */

static void*
test_score_setup(const MunitParameter params[], void* user_data) {

  Bge_Matrix* scoring_data = BgeMatrixCreate(3, 20);

  double dat[60] = {
                    -0.78,    -1.55,     0.11,
                    0.18,    -3.04,    -2.35,
                    1.87,     1.04,     0.48,
                    -0.42,    0.27,   -0.68,
                    1.23,    1.52,    0.31,
                    0.51,   -0.22,   -0.60,
                    0.44,   -0.18,
                    0.13,    0.57,   -1.82,
                    -2.76,    0.64,    0.47,
                    0.74,    1.05,    0.15,
                    0.20,    0.43,    2.13,
                    0.63,    0.16,   -0.94,
                    -1.96,    1.64,    1.25,
                    1.03,   -0.52,
                    -2.18,   -2.31,   -0.37,
                    -1.30,   -0.70,    1.35,
                    0.87,    0.23,    1.44,
                    -0.83,   -1.61,   -0.55,
                    -1.33,   -1.67,    0.79,
                    -0.62,   -2.00,    0.53,
                    -0.93,   -2.92
  };

  int i;
  for( i = 0; i < 60; i++)
    scoring_data->items[i] = dat[i];
  
  return scoring_data;

}

/* declares a dataset to be used when calculating a functions used in bge_posterior such
 * as sample_mean and sample_variance */
static void*
test_sample_setup(const MunitParameter params[], void* user_data) {

  Bge_Matrix* sample_data = BgeMatrixCreate(3,5);

  double dat[15] = {4.0, 2.0, 0.60,
                    4.2,    2.1,    0.59,
                    3.9,    2.0,    0.58,
                    4.3,   2.1,   0.62,
                    4.1,   2.2,   0.63};
  int i;
  for( i = 0; i < 15; i++)
    scoring_data->items[i] = dat[i];

  return sample_data;
}

/* tear down function to delete the test data matrices */
static void
test_tear_down(void* data)
{
  Bge_Matrix* matrix = (Bge_Matrix*) data;
  BgeMatrixDelete(&matrix);
}

/* Declare test data sets - END */

/* ------- Vector Tests ------- */

/* Tests the dot product functionality for vectors of the same size */
static MunitResult
test_dot_product(const MunitParameter params[], void* data) {

   double output;
   Bge_Vector* test_vec_1 = BgeVectorCreate(3);
   Bge_Vector* test_vec_2 = BgeVectorCreate(3);

   test_vec_1->items[0] = 1.0;
   test_vec_1->items[1] = 2.0;
   test_vec_1->items[2] = 3.0;
   
   test_vec_2->items[0] = 1.0;
   test_vec_2->items[1] = 2.0;
   test_vec_2->items[2] = 3.0;
   
   output = BgeVectorDotProduct(test_vec_1,test_vec_2);

   /* expected value = 14 */
   munit_assert_double_equal(output, 14, 2);

   BgeVectorDelete(&test_vec_1);
   BgeVectorDelete(&test_vec_2);
  
   return MUNIT_OK;
}

/* Tests the scalar multiplication functionality for vectors of the same size */
static MunitResult
test_scalar_multiplication(const MunitParameter params[], void* data) {

  Bge_Vector* test_vec_1 = BgeVectorCreate(5);

  double scalar = 7.532;
  
  test_vec_1->items[0] = 4.321;
  test_vec_1->items[1] = 5.643;
  test_vec_1->items[2] = 6.430;
  test_vec_1->items[3] = 1.923;
  test_vec_1->items[4] = 3.648;

  BgeVectorScalarMultiplication(scalar, test_vec_1);

  munit_assert_double_equal(test_vec_1->items[0], 32.545772, 6);
  munit_assert_double_equal(test_vec_1->items[1], 42.503076, 6);
  munit_assert_double_equal(test_vec_1->items[2], 48.430760, 6);
  munit_assert_double_equal(test_vec_1->items[3], 14.484036, 6);
  munit_assert_double_equal(test_vec_1->items[4], 27.476736, 6);

  BgeVectorDelete(&test_vec_1);
  
  return MUNIT_OK;
}

/* Tests the subtraction functionality between two vectors of the same size */
static MunitResult
test_subtraction(const MunitParameter params[], void* data) {

   Bge_Vector* test_vec_1 = BgeVectorCreate(3);
   Bge_Vector* test_vec_2 = BgeVectorCreate(3);
   Bge_Vector* output_vec = BgeVectorCreate(3);

   test_vec_1->items[0] = 10.0;
   test_vec_1->items[1] = 5.4;
   test_vec_1->items[2] = 8.0;
   
   test_vec_2->items[0] = 3.0;
   test_vec_2->items[1] = 2.5;
   test_vec_2->items[2] = 3.2;
   
   BgeVectorSubtraction(test_vec_1, test_vec_2, output_vec);
   
   munit_assert_double_equal(output_vec->items[0], 7.0, 1);
   munit_assert_double_equal(output_vec->items[1], 2.9, 1);
   munit_assert_double_equal(output_vec->items[2], 4.8, 1);

   BgeVectorDelete(&test_vec_1);
   BgeVectorDelete(&test_vec_2);
   BgeVectorDelete(&output_vec);
  
   return MUNIT_OK;
}

/* Tests the outer product functionality for vectors of the same size */
static MunitResult
test_outer_product(const MunitParameter params[], void* data) {

  Bge_Vector* test_vec_1 = BgeVectorCreate(3);
  Bge_Vector* test_vec_2 = BgeVectorCreate(3);
  Bge_Matrix* output_matrix = BgeMatrixCreate(3,3);

  test_vec_1->items[0] = 1.0;
  test_vec_1->items[1] = 2.0;
  test_vec_1->items[2] = 3.0;

  test_vec_2->items[0] = 1.0;
  test_vec_2->items[1] = 2.0;
  test_vec_2->items[2] = 3.0;

  BgeVectorOuterProduct(test_vec_1,test_vec_2,output_matrix);

  munit_assert_double_equal(output_matrix->items[0], 1, 2);
  munit_assert_double_equal(output_matrix->items[1], 2, 2);
  munit_assert_double_equal(output_matrix->items[2], 3, 2);
  munit_assert_double_equal(output_matrix->items[3], 2, 2);
  munit_assert_double_equal(output_matrix->items[4], 4, 2);
  munit_assert_double_equal(output_matrix->items[5], 6, 2);
  munit_assert_double_equal(output_matrix->items[6], 3, 2);
  munit_assert_double_equal(output_matrix->items[7], 6, 2);
  munit_assert_double_equal(output_matrix->items[8], 9, 2);

  BgeVectorDelete(&test_vec_1);
  BgeVectorDelete(&test_vec_2);
  BgeMatrixDelete(&output_matrix);

  return MUNIT_OK;
}

/* ------- Matrice Tests ------- */

/* tests the log determinant function for correctness by passing a square matrix */
static MunitResult
test_log_determinant(const MunitParameter params[], void* data) {

   double det;
   Bge_Matrix* test_mat = BgeMatrixCreate(3,3);

   
   test_mat->items[0] = 46057.80; test_mat->items[1] = 91353.05; test_mat->items[2] =  -7.62;
   test_mat->items[3] = 91353.05; test_mat->items[4] = 202706.99; test_mat->items[5] = 268.47;
   test_mat->items[6] = -7.62;    test_mat->items[7] = 268.47; test_mat->items[8] = 19903.92;
   
   det = BgeMatrixLogDeterminant(test_mat);
   
   munit_assert_double_equal(det, 30.6, 1);

   BgeMatrixDelete(&test_mat);

   return MUNIT_OK;
   
}

/* Tests the creation of the parent posterior for correctness */
static MunitResult
test_matrix_set_parent_posterior(const MunitParameter params[], void * data)
{
   Bge_Matrix* sub_matrix = BgeMatrixCreate(3,3);
   Bge_Matrix* parent_matrix = BgeMatrixCreate(2,2);

   int i;
   int dat[9] = {1,2,3,2,4,5,3,5,6};

   for( i = 0; i < 9; i++)
     sub_matrix->items[i] = dat[i];

   BgeMatrixSetPosteriorParentMatrix(sub_matrix, parent_matrix);

   munit_assert_int(parent_matrix->items[0], ==, sub_matrix->items[4]);
   munit_assert_int(parent_matrix->items[1], ==, sub_matrix->items[5]);
   munit_assert_int(parent_matrix->items[2], ==, sub_matrix->items[7]);
   munit_assert_int(parent_matrix->items[3], ==, sub_matrix->items[8]);
   
   BgeMatrixDelete(&sub_matrix);
   BgeMatrixDelete(&parent_matrix);
  
   return MUNIT_OK;
}

/* Ensures that the sub posterior is set correctly with the node columns/rows being the
first columns/rows in the sub posterior */

static MunitResult
test_matrix_set_sub_posterior(const MunitParameter params[], void * data)
{
   int node = 1;
   unsigned int * family = malloc( sizeof(unsigned int) * 2 );

   Bge_Matrix* posterior_matrix = BgeMatrixCreate(3,3);
   Bge_Matrix* sub_matrix = BgeMatrixCreate(2,2);

   int i;
   int dat[9] = {1,2,3,2,4,5,3,5,6};

   
   family[0] = node;
   family[1] = 0;

   for( i = 0; i < 9; i++)
     posterior_matrix->items[i] = dat[i];

   BgeMatrixSetPosteriorSubMatrix(family, 2, posterior_matrix, sub_matrix);

   munit_assert_int(sub_matrix->items[0], ==, posterior_matrix->items[4]);
   munit_assert_int(sub_matrix->items[1], ==, posterior_matrix->items[1]);
   munit_assert_int(sub_matrix->items[2], ==, posterior_matrix->items[3]);
   munit_assert_int(sub_matrix->items[3], ==, posterior_matrix->items[0]);

   free(family);
   BgeMatrixDelete(&posterior_matrix);
   BgeMatrixDelete(&sub_matrix);
   
   return MUNIT_OK;
}

/* Tests the matrix scalar multiplication operation */
static MunitResult
test_matrix_scalar_multiplication(const MunitParameter params[], void * data)
{
   Bge_Matrix* test_matrix = BgeMatrixCreate(3,3);

   int i;
   for( i = 0; i < 9; i++)
     test_matrix->items[i] = 1;

   BgeMatrixScalarMultipliciation(0.786, test_matrix);

   for( i = 0; i < 9; i++)
     munit_assert_double_equal(test_matrix->items[i], 0.786, 3);

   BgeMatrixDelete(&test_matrix);
   
   return MUNIT_OK;
}

/* Tests the matrix addition operation between two square matrices */
static MunitResult
test_matrix_addition(const MunitParameter params[], void* data) {

   Bge_Matrix* test_mat_1 = BgeMatrixCreate(3,3);
   Bge_Matrix* test_mat_2 = BgeMatrixCreate(3,3);
   Bge_Matrix* output_matrix = BgeMatrixCreate(3,3);

   int i;
   double val;
   for( i = 0; i < 9; i++)
   {
     val = (i+1)/10.0;
     test_mat_1->items[i] = val;
     test_mat_2->items[i] = val;
   }

   
   BgeMatrixAddition(test_mat_1, test_mat_2, output_matrix);

   for( i = 0; i < 9; i++)
     munit_assert_double_equal(output_matrix->items[i], (i+1)/5.0, 1);
   
   BgeMatrixDelete(&test_mat_1);
   BgeMatrixDelete(&test_mat_2);
   BgeMatrixDelete(&output_matrix);
      
   return MUNIT_OK;
}

/* ------- Matrice Tests - END ------- */

/* ------- Posterior Tests - BEGIN ------- */


/* Ensures the mean vector used in setting the posterior matrix
 * and sample variance is set correctly */
static MunitResult
test_sample_mean(const MunitParameter params[], void* data)
{
   //test data from http://www.itl.nist.gov/div898/handbook/pmc/section5/pmc541.html

   Bge_Vector* mean_vec = BgeVectorCreate(3);
   Bge_Matrix* sample_data = (Bge_Matrix*) data;

   SetSampleMean(sample_data, mean_vec);

   munit_assert_double_equal(4.100, mean_vec->items[0], 2);
   munit_assert_double_equal(2.080, mean_vec->items[1], 2);
   munit_assert_double_equal(0.604, mean_vec->items[2], 3);

   BgeVectorDelete(&mean_vec);
   
   return MUNIT_OK;
}

/* Ensures that the sample variance matrix is set correctly */
static MunitResult
test_sample_variance(const MunitParameter params[], void* data)
{

  //test data from http://www.itl.nist.gov/div898/handbook/pmc/section5/pmc541.html

  Bge_Matrix* sample_data = (Bge_Matrix*) data;
  Bge_Vector* mean_vec = BgeVectorCreate(3);
  Bge_Matrix* sample_variance = BgeMatrixCreate(3,3);

  SetSampleMean(sample_data, mean_vec);
  SetSampleVariance(sample_data, mean_vec, sample_variance);

  munit_assert_double_equal(sample_variance->items[0], 0.02500*4, 4);
  munit_assert_double_equal(sample_variance->items[1], 0.00750*4, 4);
  munit_assert_double_equal(sample_variance->items[2], 0.00175*4, 4);
  munit_assert_double_equal(sample_variance->items[3], 0.00750*4, 4);
  munit_assert_double_equal(sample_variance->items[4], 0.00700*4, 4);
  munit_assert_double_equal(sample_variance->items[5], 0.00135*4, 4);
  munit_assert_double_equal(sample_variance->items[6], 0.00175*4, 4);
  munit_assert_double_equal(sample_variance->items[7], 0.00135*4, 4);
  munit_assert_double_equal(sample_variance->items[8], 0.00043*4, 4);

  BgeMatrixDelete(&sample_variance);
  BgeVectorDelete(&mean_vec);
  
  return MUNIT_OK;
}

/* Ensure that the prior matrix is set correctly and all values are above 0 */
static MunitResult
test_prior_matrix(const MunitParameter params[], void * data){

   int n = 3;
   Bge_Matrix* test_mat_1 = BgeMatrixCreate(n,n);

   SetPriorParametricMatrix(n, 1, n+2, test_mat_1);

   munit_assert_double_equal(test_mat_1->items[0], 0.5, 1);
   munit_assert_double_equal(test_mat_1->items[1], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[2], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[3], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[4], 0.5, 1);
   munit_assert_double_equal(test_mat_1->items[5], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[6], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[7], 0.0, 1);
   munit_assert_double_equal(test_mat_1->items[8], 0.5, 1);

   BgeMatrixDelete(&test_mat_1);
   
   return MUNIT_OK;
}

/* This test tests the posterior matrix for symmetry as it is difficult to create an example
 * of a posterior matrix by hand */
static MunitResult
test_posterior_matrix(const MunitParameter params[], void* data) {

  int alpha_mu = 1;
  int alpha_omega = 5;

  Bge_Matrix* scoring_data = (Bge_Matrix*) data;
  Bge_Matrix* prior_matrix = BgeMatrixCreate(3,3);
  Bge_Matrix* posterior_matrix = BgeMatrixCreate(3,3);

  SetPriorParametricMatrix(3, alpha_mu, alpha_omega,prior_matrix);
  SetPosteriorParametricMatrix(scoring_data, prior_matrix, posterior_matrix,
    alpha_mu, alpha_omega, NULL);

  /* testing for symmetry */
  munit_assert_double_equal(posterior_matrix->items[1], posterior_matrix->items[3], 3);
  munit_assert_double_equal(posterior_matrix->items[2], posterior_matrix->items[6], 3);
  munit_assert_double_equal(posterior_matrix->items[5], posterior_matrix->items[7], 3);

  BgeMatrixDelete(&prior_matrix);
  BgeMatrixDelete(&posterior_matrix);
  
  return MUNIT_OK;

}

/* Posterior Tests - END */

/* Scoring Tests - BEGIN */

/* This test tests that the log gamma ratio tables are correctly set
 * (tests to check if the ratio increases as number of parents increases) */
static MunitResult
test_score_log_gamma_ratio(const MunitParameter params[], void * data)
{
  int alpha_omega = 6;
  int no_vars = 4;
  int no_samples = 1000;

  double * table = create_log_gamma_ratio_table(no_samples, alpha_omega, no_vars);

  munit_assert_double(table[0], <, table[1]);
  munit_assert_double(table[1], <, table[2]);
  munit_assert_double(table[2], <, table[3]);

  free(table);
  
  return MUNIT_OK;
}

/* This tests scores two score equivelent networks to check if they
 * recieve the same score */
static MunitResult
test_score_equivalence(const MunitParameter params[], void * data)
{
  Bge_Matrix* scoring_data = (Bge_Matrix*) data;
  Bge_Matrix* prior_matrix = BgeMatrixCreate(3,3);
  Bge_Matrix* posterior_matrix = BgeMatrixCreate(3,3);

  int alpha_mu = 1;
  int alpha_omega = 5;

  double score_1;
  double score_2;
  double score_3;
  double score_4;
  double score_5;
  double score_6;
  double score_7;
  double score_8;
  double score_9;

  double network_score_1;
  double network_score_2;
  double network_score_3;
  
  double log_prefactor = 0.5 * (log(alpha_mu) - log(alpha_mu + 20));
  double * log_gamma_ratio_table = create_log_gamma_ratio_table(20, alpha_omega, 3);

  unsigned int * famB_1 = malloc(sizeof( unsigned int ) * 2);
  unsigned int * famC_1 = malloc(sizeof( unsigned int ) * 2);
  unsigned int * famA_2 = malloc(sizeof( unsigned int ) * 2);
  unsigned int * famB_2 = malloc(sizeof( unsigned int ) * 2);
  unsigned int * famA_3 = malloc(sizeof( unsigned int ) * 2);
  unsigned int * famC_3 = malloc(sizeof( unsigned int ) * 2);

  SetPriorParametricMatrix(3, alpha_mu, alpha_omega, prior_matrix);
  SetPosteriorParametricMatrix(scoring_data, prior_matrix, posterior_matrix, alpha_mu, alpha_omega, NULL);

  /* network 1 - (a->b->c) */

  famB_1[0] = 1;
  famB_1[1] = 0;
  famC_1[0] = 2;
  famC_1[1] = 1;

  /* don't use scorecache for unit test so last two arguments are NULL */
  
  score_1 = LogBgeScore(0, NULL, NULL, 0, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_2 = LogBgeScore(1, famB_1, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_3 = LogBgeScore(2, famC_1, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  free(famB_1);
  free(famC_1);
  
  /* network 2 - (a<-b<-c) */

  famA_2[0] = 0;
  famA_2[1] = 1;
  famB_2[0] = 1;
  famB_2[1] = 2;

  score_4 = LogBgeScore(0, famA_2, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_5 = LogBgeScore(1, famB_2, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_6 = LogBgeScore(2, NULL, NULL, 0, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  free(famA_2);
  free(famB_2);
  
  /* network 3 - (a->b<-c) */

  famA_3[0] = 0;
  famA_3[1] = 1;
  famC_3[0] = 2;
  famC_3[1] = 1;

  score_7 = LogBgeScore(0, famA_3, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_8 = LogBgeScore(1, NULL, NULL, 0, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  score_9 = LogBgeScore(2, famC_3, NULL, 1, alpha_mu, alpha_omega,log_prefactor,
    log_gamma_ratio_table, prior_matrix, posterior_matrix, scoring_data,NULL,NULL);

  free(famA_3);
  free(famC_3);

  /* add up local scores for each network */

  network_score_1 = score_1 + score_2 + score_3;
  network_score_2 = score_4 + score_5 + score_6;
  network_score_3 = score_7 + score_8 + score_9;

  /* check for score equivalence between the 3 networks */
  munit_assert_double_equal(network_score_1, network_score_2, 4);
  munit_assert_double_equal(network_score_2, network_score_3, 4);

  free(log_gamma_ratio_table);
  BgeMatrixDelete(&prior_matrix);
  BgeMatrixDelete(&posterior_matrix);

  return MUNIT_OK;
}

/* Scoring Tests - END */
#endif

static MunitResult
test_scorecache(const MunitParameter params[], void* data) {

  SCIP* scip;
  SCORECACHE* scorecache;

  /* OK to cache */
  VARIABLE variables1[4] = {0,1,2,5};
  int nvariables1 = 4;

  /* subset too big to cache */
  VARIABLE variables2[6] = {1,2,3,5,6,7};
  int nvariables2 = 6;

  /* contains elements which are too big */
  VARIABLE variables3[6] = {1,10};
  int nvariables3 = 2;

  int rank;
  COUNT count;
  
  int nvars = 10;              /**< scorecache intended for subsets of {0,1,2,3,4,5,6,7,8,9} */
  int nvarscachelimit = 5;     /**< subsets must have size below this to be cached. */
  int cachesizelimit = 200;    /**< the maximum number of scores and count 
                                  values to cache (limit is common to both). */
  int cacheblocksize = 5;    /**< how much to increase the size of the cache for scores 
                                  and counts when it is too small (common to both).  */

  SCORE skore;

  SCIP_CALL( SCIPcreate(&scip) );

  SCIP_CALL( make_scorecache(scip, &scorecache, nvars,
      nvarscachelimit, cachesizelimit, cacheblocksize) );

  /* since nothing is stored, should get a count of 0 always */
  get_score_count_rank(scorecache,variables1,nvariables1,&rank,&count);
  munit_assert_int(rank, ==, 181); /* TODO: check this is the correct rank */
  munit_assert_int(count, ==, 0);
  get_score_count_rank(scorecache,variables2,nvariables2,&rank,&count);
  munit_assert_int(rank, ==, -1); 
  munit_assert_int(count, ==, 0);
  /* variables3 = {1,10} and so not a subset of {0,1,2,3,4,5,6,7,8,9} 
     nonetheless no error is thrown since there is no check for performance reasons */
  get_score_count_rank(scorecache,variables3,nvariables3,&rank,&count);
  munit_assert_int(count, ==, 0);

  /* now store something */
  get_score_count_rank(scorecache,variables1,nvariables1,&rank,&count);
  munit_assert_int(rank, ==, 181); /* TODO: check this is the correct rank */
  munit_assert_int(count, ==, 0);
  SCIP_CALL( set_score_count_from_rank(scip,scorecache,rank,-1.2,30) );

  /* and check we get it back */
  skore = get_score_count_rank(scorecache,variables1,nvariables1,&rank,&count);
  munit_assert_int(rank, ==, 181); /* TODO: check this is the correct rank */
  munit_assert_double_equal(skore, -1.2, 8);
  munit_assert_int(count, ==, 30);

  delete_scorecache(scip, &scorecache);  

  SCIP_CALL( SCIPfree(&scip) );

  return MUNIT_OK;
}

/* Run Tests - BEGIN */

static MunitTest tests[] =
{
#ifdef BLAS
  {
    (char*) "/vector/dot_product", /* IMPLEMENTED */
    test_dot_product,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/vector/scalar_multiplication", /* IMPLEMENTED */
    test_scalar_multiplication,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/vector/subtraction", /* IMPLEMENTED */
    test_subtraction,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/vector/outer_product", /* IMPLEMENTED */
    test_outer_product,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/matrix/log_determinant", /* IMPLEMENTED */
    test_log_determinant,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/matrix/parent_posterior", /* IMPLEMENTED */
    test_matrix_set_parent_posterior,
    test_score_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/matrix/sub_posterior", /* IMPLEMENTED */
    test_matrix_set_sub_posterior,
    test_score_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/matrix/scalar_multiplication", /* IMPLEMENTED */
    test_matrix_scalar_multiplication,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/matrix/addition", /* IMPLEMENTED */
    test_matrix_addition,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/posterior/sample_mean", /* IMPLEMENTED */
    test_sample_mean,
    test_sample_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/posterior/sample_variance", /* IMPLEMENTED */
    test_sample_variance,
    test_sample_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
   },

  {
    (char*) "/posterior/prior_matrix", /* IMPLEMENTED */
    test_prior_matrix,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
   },

  {
    (char*) "/posterior/posterior_matrix", /* IMPLEMENTED */
    test_posterior_matrix,
    test_score_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  {
    (char*) "/score/log_gamma_ratio", /* IMPLEMENTED */
    test_score_log_gamma_ratio,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  { (char*) "/score/equivalence", /* IMPLEMENTED */
    test_score_equivalence,
    test_score_setup,
    test_tear_down,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },
#endif

  {
    (char*) "/scorecache/", /* IMPLEMENTED */
    test_scorecache,
    NULL,
    NULL,
    MUNIT_TEST_OPTION_NONE,
    NULL
  },

  
  { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL }

};

static const MunitSuite test_suite = {(char*) "/gobnilp", tests, NULL, 1, MUNIT_SUITE_OPTION_NONE};


int main(int argc, char* argv[MUNIT_ARRAY_PARAM(argc + 1)])
{
  return munit_suite_main(&test_suite, (void*) "", argc, argv);
}

/* Run Tests - END */
